package principal;

// <editor-fold defaultstate="collapsed" desc="LIBRERIAS">                          
import java.io.EOFException;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Observable;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
// </editor-fold>         

public class Servidor extends Observable {

    // <editor-fold defaultstate="collapsed" desc="ATRIBUTOS">                          
    private ObjectOutputStream salida;
    private ObjectInputStream entrada;
    private ServerSocket servidor;
    private Socket conexion;
    private int contador = 1;
    String msg = "-1";
// </editor-fold>         

    // <editor-fold defaultstate="collapsed" desc="CONSTRUCTOR">                          
    public Servidor() {

        Runnable hilo = new Runnable() {
            @Override
            public void run() {
                ejecutarServidor();
            }
        };

        Thread h = new Thread(hilo);
        h.start();

    }
// </editor-fold>         

    // <editor-fold defaultstate="collapsed" desc="METODOS">                          
    public void ejecutarServidor() {
        // configurar servidor para que reciba conexiones; procesar las conexiones
        try {

            // Paso 1: crear un objeto ServerSocket.
            servidor = new ServerSocket(28001, 100);

            while (true) {

                try {
                    esperarConexion(); // Paso 2: esperar una conexión.
                    obtenerFlujos();        // Paso 3: obtener flujos de entrada y salida.
                    procesarConexion(); // Paso 4: procesar la conexión.
                } // procesar excepción EOFException cuando el cliente cierre la conexión 
                catch (EOFException excepcionEOF) {
                    JOptionPane.showMessageDialog(null, "El servidor ha cerrado");
                } finally {
                    cerrarConexion();   // Paso 5: cerrar la conexión.
                    ++contador;
                }

            } // fin de instrucción while

        } // fin del bloque try
        // procesar problemas con E/S
        catch (IOException excepcionES) {
            JOptionPane.showMessageDialog(null, "El cliente ha perdido");
        }

    } // fin del método ejecutarServidor

    // esperar que la conexión llegue, después mostrar información de la conexión
    private void esperarConexion() throws IOException {
        mostrarMensaje("Esperando una conexión\n");
        conexion = servidor.accept(); // permitir al servidor aceptar la conexión            
        mostrarMensaje("Conexión " + contador + " recibida de: "
                + conexion.getInetAddress().getHostName());
    }

    // obtener flujos para enviar y recibir datos
    private void obtenerFlujos() throws IOException {
        // establecer flujo de salida para los objetos
        salida = new ObjectOutputStream(conexion.getOutputStream());
        salida.flush(); // vaciar búfer de salida para enviar información de encabezado

        // establecer flujo de entrada para los objetos
        entrada = new ObjectInputStream(conexion.getInputStream());

        mostrarMensaje("\nSe recibieron los flujos de E/S\n");
    }

    // procesar la conexión con el cliente
    public void procesarConexion() throws IOException {
        // enviar mensaje de conexión exitosa al cliente
        // enviar mensaje de conexión exitosa al cliente
        String mensaje = "-1";
        enviarDatos(mensaje);

        // habilitar campoIntroducir para que el usuario del servidor pueda enviar mensajes
        establecerCampoTextoEditable(true);

        do { // procesar los mensajes enviados por el cliente

            // leer el mensaje y mostrarlo en pantalla
            try {
                mensaje = (String) entrada.readObject();
                msg = mensaje;
                mostrarMensaje("\n" + mensaje);

                System.out.println("Servidor");
                this.setChanged();
                this.notifyObservers();
            } // atrapar problemas que pueden ocurrir al tratar de leer del cliente
            catch (ClassNotFoundException excepcionClaseNoEncontrada) {
                JOptionPane.showMessageDialog(null, "Dato Desconocido");
            }

        } while (!mensaje.equals("CLIENTE>>> TERMINAR"));

    } // fin del método procesarConexion

    // cerrar flujos y socket
    private void cerrarConexion() {
        mostrarMensaje("\nFinalizando la conexión\n");
        establecerCampoTextoEditable(false); // deshabilitar campoIntroducir

        try {
            salida.close();
            entrada.close();
            conexion.close();
        } catch (IOException excepcionES) {
            JOptionPane.showMessageDialog(null, "Error al cerrar los flujos");
        }
    }

    // enviar mensaje al cliente
    public void enviarDatos(String mensaje) {
        // enviar objeto al cliente
        try {
            salida.writeObject(mensaje);
            salida.flush();
            mostrarMensaje("\nSERVIDOR>>> " + mensaje);
        } // procesar problemas que pueden ocurrir al enviar el objeto
        catch (IOException excepcionES) {
        }
    }

    public String getMsg() {
        return msg;
    }

    // método utilitario que es llamado desde otros subprocesos para manipular a
    // areaPantalla en el subproceso despachador de eventos
    private void mostrarMensaje(final String mensajeAMostrar) {
        // mostrar mensaje del subproceso de ejecución despachador de eventos
        SwingUtilities.invokeLater(
                new Runnable() {  // clase interna para asegurar que la GUI se actualice apropiadamente
                    public void run() // actualiza areaPantalla
                    {
//               areaPantalla.append( mensajeAMostrar );
//               areaPantalla.setCaretPosition( 
//                  areaPantalla.getText().length() );
                    }
                } // fin de la clase interna
                ); // fin de la llamada a SwingUtilities.invokeLater
    }

    // método utilitario que es llamado desde otros subprocesos para manipular a 
    // campoIntroducir en el subproceso despachador de eventos
    private void establecerCampoTextoEditable(final boolean editable) {
        // mostrar mensaje del subproceso de ejecución despachador de eventos
        SwingUtilities.invokeLater(
                new Runnable() {  // clase interna para asegurar que la GUI se actualice apropiadamente
                    public void run() // establece la capacidad de modificar a campoIntroducir
                    {
//               campoIntroducir.setEditable( editable );
                    }
                } // fin de la clase interna
                ); // fin de la llamada a SwingUtilities.invokeLater
    }
// </editor-fold>         
}
